package com.redijedi.tapestry5.components;

import java.util.Iterator;

import org.apache.tapestry.ComponentResources;
import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.annotations.AfterRender;
import org.apache.tapestry.annotations.AfterRenderTemplate;
import org.apache.tapestry.annotations.BeforeRenderTemplate;
import org.apache.tapestry.annotations.BeginRender;
import org.apache.tapestry.annotations.Environmental;
import org.apache.tapestry.annotations.Inject;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.annotations.SetupRender;
import org.apache.tapestry.services.Heartbeat;

import com.redijedi.tapestry5.TreeModelRenderer;
import com.redijedi.tapestry5.TreeNodeModel;
import com.redijedi.tapestry5.internal.TreeModelRendererImpl;
import com.redijedi.tapestry5.internal.TreeNodeModelWrapper;

/**
 * Implements a UL based Tree from a hierarchical data source. This code was
 * originally based on code by Erik Vullings
 * http://wiki.apache.org/tapestry/Tapestry5HowToCreateYourOwnComponents. The
 * current implementation is vastly different. This implementations is model
 * based.
 * 
 * @author torr
 */
public class Tree {

	@Environmental
	private Heartbeat _heartbeat;

	@Inject
	private ComponentResources _resources;

	@Parameter(required = true, defaultPrefix = "prop")
	private Object _model;

	private TreeNodeModelWrapper _headNode;

	private TreeNodeModelWrapper _currNode;

	private Iterator<TreeNodeModelWrapper> _iterator;

	private TreeModelRenderer _renderer;

	@SetupRender
	boolean setup(MarkupWriter writer) {
		if (_model instanceof Iterable) {
			_headNode = defaultModel();
		}
		if (_model instanceof TreeNodeModel) {
			_headNode = new TreeNodeModelWrapper((TreeNodeModel) _model);
		}
		if (_headNode == null) {
			return false;
		}

		_currNode = _headNode;

		_renderer = new TreeModelRendererImpl(writer);

		// initialize the iterator to move over the children
		_iterator = _currNode.getChildren().iterator();

		return true;
	}

	@BeginRender
	void begin() {
		_heartbeat.begin();
	}

	@BeforeRenderTemplate
	void before() {
		_renderer.preRender(_currNode);
	}

	@AfterRenderTemplate
	void after() {
		_renderer.postRender(_currNode);
	}

	@AfterRender
	boolean end() {
		_currNode = walk();
		_heartbeat.end();
		// quit when we get back to the head
		return (_currNode == _headNode);
	}

	private TreeNodeModelWrapper walk() {
		TreeNodeModelWrapper nextNode = null;
		if (_iterator.hasNext()) {
			nextNode = _iterator.next();
		}
		return nextNode;
	}

	// TODO implement
	@SuppressWarnings("unchecked")
	private TreeNodeModelWrapper defaultModel() {
		Class valueType = _resources.getBoundType("value");

		if (valueType == null) {
			return null;
		}

		// handle Collection types
		if (Iterable.class.isAssignableFrom(valueType)) {
			// return InternalUtils.treeModelFromIterable((Iterable) _model);
		}

		return null;
	}

}
